using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using FilteredStatistics.Controller;

namespace FilteredStatistics.Data
{
    class FilterListWithCache : FilterList
    {
        public FilterListWithCache(IActivity activity) :
            base(activity)
        {
        }

        protected override void OnFilterChanged(Filter filter, PropertyChangedEventArgs changedProperty)
        {
            InvalidateFilteredCache(filter);

            base.OnFilterChanged(filter, changedProperty);
        }

        public override FilterList Clone()
        {
            FilterListWithCache copy = new FilterListWithCache(Activity);

            copy.m_Filters.Clear();
            foreach (Filter currentFilter in m_Filters)
            {
                copy.AddFilter(currentFilter.Clone());
            }

            return copy;
        }

        protected void InvalidateFilteredCache(IActivity activity)
        {
            InvalidateFilteredCache(0);
        }

        protected void InvalidateFilteredCache(Filter invalidFilter)
        {
            int filterIndex = m_Filters.IndexOf(invalidFilter);

            if (filterIndex == -1)
            {
                filterIndex = 0;
            }

            InvalidateFilteredCache(filterIndex);
        }

        protected void InvalidateFilteredCache(int filterIndex)
        {
            Debug.Assert(filterIndex != -1);

            if (filterIndex < m_FilteredDataCache.Count)
            {
                // We already have a cached item for this filter, delete it and
                // all the following caches, we will need to refresh them
                m_FilteredDataCache.RemoveRange(filterIndex, m_FilteredDataCache.Count - filterIndex);
            }
        }

        protected void RefreshCachedInfo()
        {
            // We must now recreate new data for our missing entries
            if (Activity != null && m_FilteredDataCache.Count != m_Filters.Count)
            {
                for (int i = m_FilteredDataCache.Count; i < m_Filters.Count; ++i)
                {
                    if (m_Filters[i].CriteriaFacade != null)
                    {
                        // Create a new set of entries from our last valid cached filter data
                        IFilteredDataSet newFilteredData = null;
                        IFilteredDataSet previousDataSet = null;

                        if (i == 0)
                        {
                            previousDataSet = WholeActivityFilteredDataSet.Instance;
                        }
                        else
                        {
                            previousDataSet = m_FilteredDataCache[i - 1];
                        }

                        newFilteredData = new BasicFilteredDataSet(Activity, m_Filters[i], previousDataSet.GetFilteredTimes());
                        m_FilteredDataCache.Add(newFilteredData);
                    }
                }
            }
        }

        public override void AddFilter(Filter filter)
        {
            Debug.Assert(!m_Filters.Contains(filter));

            m_Filters.Add(filter);
            filter.FilterChanged += new Filter.FilterChangedEventHandler(OnFilterChanged);

            InvalidateFilteredCache(filter);

            // Don't trigger the event when we add an empty filter (placeholder for editing)
            if (filter.IsValid)
            {
                TriggerFilterListChangedEvent("Filters");
            }
            else
            {
                TriggerFilterListChangedEvent("NewPlaceholderFilter");
            }
        }

        public override void RemoveFilter(int index)
        {
            Debug.Assert(m_Filters.Count > index);

            m_Filters[index].FilterChanged -= new Filter.FilterChangedEventHandler(OnFilterChanged);
            m_Filters.RemoveAt(index);

            InvalidateFilteredCache(index);

            TriggerFilterListChangedEvent("Filters");
        }

        public override FilterResults GetMatchingRanges()
        {
            RefreshCachedInfo();

            if (m_FilteredDataCache.Count > 0)
            {
                return m_FilteredDataCache[m_FilteredDataCache.Count - 1].GetFilteredTimes();
            }
            else if (Activity != null)
            {
                return WholeActivityFilteredDataSet.Instance.GetFilteredTimes();
            }

            return new FilterResults();
        }

        public override IActivity Activity
        {
            get { return base.Activity; }
            set
            {
                if (Activity != value)
                {
                    base.Activity = value;

                    InvalidateFilteredCache(Activity);
                }
            }
        }

        private List<IFilteredDataSet> m_FilteredDataCache = new List<IFilteredDataSet>();
    }
}
